/* ================================================================================
//	Crypteviant!
//	Providing tough encrypted P2P Chat
//	Copyright (C) 2010  Martin Pfeifer, Tobias Rausch
//
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
// ============================================================================== */

#include "testtimer.hpp"


// Namespaces
using namespace Timer;

void TestTimer::checkInitialTimerState(AbstractTimer *timer) const
{
    // Check whether this has worked
    QVERIFY2(timer != NULL, "Timer object is NULL");

    // Check the initial values of the Timer
    QCOMPARE(timer->getState(), AbstractTimer::INITIAL);
    QCOMPARE(timer->getStopTime(), 0UL);
    QCOMPARE(timer->getDifference(), 0UL);
    QVERIFY2(timer->getStartTime() != 0UL, "Timer was not initialized with startTime");
}


void TestTimer::cleanupTimer(AbstractTimer *timer) const
{
    // Delete the object
    delete timer;
    timer = NULL;

    QVERIFY2(timer == NULL, "Timer could not be cleared");
}


void TestTimer::testFactory()
{
    AbstractTimer *timer = TimerFactory::getNativeTimer();
    checkInitialTimerState(timer);
    cleanupTimer(timer);
}


void TestTimer::testStoppingAfterConstructing()
{
    // Instanciate the native Timer
    AbstractTimer *timer = TimerFactory::getNativeTimer();
    checkInitialTimerState(timer);

    // Set up the Signal Spy
    QSignalSpy stopSpy(timer, SIGNAL(stopped(ulong)));
    QSignalSpy stopSpy2(timer, SIGNAL(stopped(ulong,ulong)));

    QTest::qWait(1); // Wait 1 ms

    // Stop the Timer
    timer->stop();

    // Check if the signals have been emitted
    QVERIFY2(stopSpy.count() == 1, "stop(long) has not been emitted");
    QVERIFY2(stopSpy2.count() == 1, "stop(long, long) has not been emitted");

    // Verify the arguments of the signals
    /**
     * @todo QVariant needs to be converted to long because the emitted signal has long values as argument
    */
    //QList<QVariant> arguments = stopSpy.takeFirst();
    //QList<QVariant> arguments2 = stopSpy2.takeFirst();
    //QCOMPARE(arguments.at(0).toInt(), timer->getDifference());
    //QCOMPARE(arguments2.at(0).toInt(), timer->getStopTime());
    //QCOMPARE(arguments2.at(1).toInt(), timer->getStartTime());

    // Check the internal states of the Timer
    QVERIFY2(timer->getStartTime() != timer->getStopTime(), "Start and Stop times are equal");
    QCOMPARE(timer->getState(), AbstractTimer::STOPPED);
    QCOMPARE(timer->getDifference(), timer->getStopTime() - timer->getStartTime());

    // Delete the object
    cleanupTimer(timer);
}


void TestTimer::testManualStartingStopping()
{
    // Instanciate a Timer
    AbstractTimer *timer = TimerFactory::getNativeTimer();
    checkInitialTimerState(timer);

    // Save the initial state of the Timer
    unsigned long startTime = timer->getStartTime();

    QTest::qWait(1); // Wait 1 ms

    // Set up the Signal Spy
    QSignalSpy startSpy(timer, SIGNAL(started(unsigned long)));

    // Start the Timer
    timer->start();

    // Check if the signal was emitted
    QVERIFY2(startSpy.count() == 1, "start(long) was not emitted");

    // Check the internal states of the Timer
    QCOMPARE(timer->getState(), AbstractTimer::STARTED);
    QVERIFY2(timer->getStartTime() != startTime, "StartTime was not reset");
    QCOMPARE(timer->getStopTime(), 0UL);
    QCOMPARE(timer->getDifference(), 0UL);

    QTest::qWait(1); // Wait 1 ms

    // Stop the Timer
    timer->stop();

    // Check the state of the Timer
    QVERIFY2(timer->getStartTime() != timer->getStopTime(), "Start and Stop times are equal");
    QCOMPARE(timer->getState(), AbstractTimer::STOPPED);
    QCOMPARE(timer->getDifference(), timer->getStopTime() - timer->getStartTime());

    // Delete the object
    cleanupTimer(timer);
}


void TestTimer::testTimerResetOnStart()
{
    // Instanciate a Timer
    AbstractTimer *timer = TimerFactory::getNativeTimer();
    checkInitialTimerState(timer);

    // Save initial state of the Timer
    unsigned long startTime = timer->getStartTime();

    QTest::qWait(1); // Wait 1 ms

    // Stop the Timer
    timer->stop();

    // Check internal states
    QCOMPARE(timer->getState(), AbstractTimer::STOPPED);
    QCOMPARE(timer->getStartTime(), startTime);
    QVERIFY2(timer->getStopTime() != 0UL, "StopTime was not set correctly");
    QVERIFY2(timer->getDifference() != 0UL, "Difference was not set correctly");

    // Restart the Timer
    timer->start();

    // Check if all internal fields are reset correctly
    QCOMPARE(timer->getState(), AbstractTimer::STARTED);
    QVERIFY2(timer->getStartTime() != startTime, "StartTime was not set correctly after restart");
    QCOMPARE(timer->getStopTime(), 0UL);
    QCOMPARE(timer->getDifference(), 0UL);

    // Delete the object
    cleanupTimer(timer);
}


void TestTimer::testTimerResetManually()
{
    // Instanciate a Timer
    AbstractTimer *timer = TimerFactory::getNativeTimer();
    checkInitialTimerState(timer);

    // Save initial state of the Timer
    unsigned long startTime = timer->getStartTime();

    // Stop the Timer
    timer->stop();

    // Check internal states
    QCOMPARE(timer->getState(), AbstractTimer::STOPPED);
    QVERIFY2(timer->getStopTime() != 0UL, "StopTime was not set correctly");

    // Reset the Timer manually
    timer->reset();

    // Check if all internal fields are reset correctly
    QCOMPARE(timer->getState(), AbstractTimer::NONE);
    QVERIFY2(timer->getStartTime() != startTime, "StartTime was not set correctly after restart");
    QCOMPARE(timer->getStopTime(), 0UL);
    QCOMPARE(timer->getDifference(), 0UL);

    // Delete the object
    cleanupTimer(timer);
}

QTEST_MAIN(TestTimer)
